package com.shujia.scala

import java.util.Scanner

object Demo02Base {
  def main(args: Array[String]): Unit = {
    // 一行注释
    /*
     多行注释
     */
    /**
     * 文档注释
     */

    // 变量的定义
    /**
     * Java vs Scala
     * Java：
     * 变量的类型
     * 变量名称
     * 赋值
     *
     * Scala：
     * 变量的类型在Scala中可以分为两种：val、var
     * val 修饰的变量 是 不可变的
     * var 修饰的变量 是 可变的（可以重新赋同类型的值）
     *
     * 格式：
     * Java：
     * 变量的类型 变量名称 = 值
     * Scala：
     * val 变量名:变量的类型 = 值
     * var 变量名:变量的类型 = 值
     * 变量命名规则：
     * 1、必须是大小写字母或者是下划线还有数字
     * 2、必须是非数字开头
     * 3、不能是关键字
     */
    // Scala中每行代码不需要加分号结尾
    // 相当于Java中的由final修饰的变量，即：常量
    val i = 1 // 不可变的
    //    i = 2 // 不能给val修饰的变量赋值

    var j = 1
    println(j)
    j = 2 // var修饰的变量可以重新赋值，注意值的类型得一致
    //    j = "2" // 会报错，类型不匹配
    println(j)

    // Scala中的变量具体的值类型可以省略，自动由值进行推断——推断类型
    val k: Int = 3
    val kk = 3

    // Java中的八大基本数据类型：byte、short、int、long、char、float、double、boolean
    // Scala中的数据类型：并不像Java是基本类型，在Scala中都是引用类型
    //   整形：Byte、Short、Int、Long
    //   浮点类型（小数）：Float、Double
    //   字符类型：Char
    //   布尔类型：Boolean
    val byte: Byte = 1
    val short: Short = 1
    val int: Int = 1
    val long: Long = 1
    val long2: Long = 1L

    val float: Float = 1.234F
    val double: Double = 1.2345

    val char: Char = 'a'

    val boolean1: Boolean = true
    val boolean2: Boolean = false

    // 类型的转换
    // 字符串转整型
    val str1: String = "123"
    // 使用Java的方式
    var i1: Int = Integer.parseInt(str1)

    // 使用Scala的方式：想要转什么类型就to什么类型
    // 本质上还是调用了Java包装类相关的类型转换方法
    // 转换时需要注意 值的格式是否符合转换要求：例如 abc就不能转数值型
    var i2: Int = str1.toInt
    // println打印函数，本质上就是Java中的System.out.println，在Scala中进行了简化
    println(str1.toByte)
    println(str1.toShort)
    println(str1.toInt)
    println(str1.toLong)
    println(str1.toFloat)
    println(str1.toDouble)
    //    println(str1.toBoolean)

    // Scala中的字符串String本质上还是Java中的String
    // 但是在Scala中多了很多方法，这些方法是通过”隐式转换“加上的
    val str2: String = "hello,java,scala"
    // 字符串常见的操作：切分，截取，拼接
    val strArr: Array[String] = str2.split(",")
    println(strArr) // 直接打印会输出地址

    /**
     * Java的增强for
     * for (String s:strArr){
     *
     * }
     */
    // Java中的遍历方式
    for (s: String <- strArr) {
      println(s)
    }

    // Scala中的遍历方式
    strArr.foreach(println)

    println(str2.substring(6, 10))

    val str3: String = str2.concat(",python")
    println(str2)
    println(str3)


    println("*" * 50)

    val str4: String = "hello,java|scala"

    // 提取每个单词，即按照,分割，又要按照|分割
    //    str4.split(",|\\|").foreach(println)

    str4 split ",|\\|" foreach println

    // 在Scala中对象调用方法时可以省略.
    // 如果调用的方法只有一个参数需要传入，则括号可以省略
    val s1: String = "*"
    println(s1.*(10))
    println(s1 * 10)
    println(10 * 10)


    // Scala中的运算符：
    // 算数运算符：+ - * / %
    val i3: Int = 10
    val i4: Int = 3

    println(i3 / i4) // 3
    println(i3 % i4) // 1
    println(i3.toDouble / i4) // 3.333333
    val d1: Double = i3.toDouble / i4
    // 保留两位小数
    println("$d1")
    println(f"$d1")
    println(f"$d1%.2f")
    // 保留3为小数
    println(d1.formatted("%.3f"))

    println(s"$d1")

    val id = "1"
    val name = "zs"
    val age = 22
    val _gender = "男"

    println(id + "," + name + "," + age)
    // Scala中的字符串可以通过s/f修饰，在字符串中就可以通过 $变量名 来将变量具体的值传入
    // f修饰的字符串还可通过 %.f 这种格式来进行格式化或者是控制长度
    println(s"$id,$name,$age")
    println(f"$id,$name,$age")
    //    println(f"$id,$name,$age,$_gender") // 下划线开头的变量名直接通过$引入编译时会报错
    println(f"$id,$name,$age,${_gender}")
    // 在Scala中还可以通过三个成对的双引号来定义字符串，一般用于SQL字符串，可以自动换行
    val sqlStr: String =
      """
        |select *
        |from tb
        |where id = '1'
        |group by name
        |""".stripMargin

    println(sqlStr)

    val s3: String = "abc"
    val s4: String = "abc"
    println(s3.equals(s4)) // true
    println(s3 == s4) // true

    // 逻辑运算符：&& || ! ^
    println(true && true) // true
    println(true || true) // true
    println(true && false) // false
    println(true || false) // true
    println(false || false) // false
    println(true ^ false) // true
    println(false ^ false) // false
    println(true ^ true) // false
    println(!true) // false

    // 位运算符：<< >> & |
    println(8 << 2) // 32 00001000 00100000
    println(8 >> 2) // 2 00000010
    println(8 & 3) // 按位与 0 00001000 00000011
    println(8 | 3) // 按位或 11

    // 赋值运算符：+= -+ *= /= ......
    var i5: Int = 10
    i5 += 1
    println(i5)
    i5 -= 1
    println(i5)
    i5 = i5 + 1
    println(i5)
    // 在Scala中没有++ --

    // 比较运算符：==、!=、> < >= <=
    // SQL比较运算符：不等于<>、等于<=>


    // 选择结构
    // 非等值的比较：if / else if / else
    val scan: Scanner = new Scanner(System.in)
    print("请输入一个年龄：")
    //    val inputAge: Int = scan.nextInt()
    val inputAge: Int = 18

    if (inputAge < 18) {
      println("童年")
    } else if (inputAge >= 18 && inputAge < 30) {
      println("中年")
    } else {
      println("老年")
    }

    // if else if else 还可以拥有返回值
    val f: Any = if (inputAge < 18) {
      // 在Scala代码中，默认最后一行是返回值，不需要加return
      // 如果加了return那么整个main方法会结束，后续的代码就不能执行了
      "童年"
    } else if (inputAge >= 18 && inputAge < 30) {
      "中年"
    } else {
      200
    }

    println(f)

    println("程序结束了")

    // 等值的比较：match 类似Java中的switch，同样也可以有返回值
    val s8: String = "scala"

    // match可以匹配：1、基本数据类型 2、字符串 3、枚举 4、样例类 5、自定义对象
    val m: String = s8 match {
      // 如果代码只有一行 {} 可以省略
      case "java" => {
        "j"
      }
      // 同理return可以省略，最后一行代码会作为返回值
      case "python" => "p"
      // 多个case不需要用break结束
      case "scala" => "s"
      // 相当于default，前面都没匹配上则返回
      case _ => "x"
    }

    println(m)

    // 循环结构：while
    // 计算1~100之和
    var cnt: Int = 1
    var sum: Int = 0
    while (cnt <= 100) {
      sum += cnt
      cnt += 1
    }
    println(sum)

    var cnt2: Int = 1
    var sum2: Int = 0
    do{
      sum2+=cnt2
      cnt2+=1
    }while(cnt2<=100)
    println(sum2)

    // Scala中没有for i循环
    // for主要用于遍历容器，通常可以结合range方法来模拟Java中的for i效果

    val s:String = "abcdefghijklmn"
    val sArr: Array[Char] = s.toCharArray
    println(sArr(5)) // 通过下标可以提取数组中的元素
    // Java风格：   for(int i=0;i<sArr.length;i++)

    for (i:Int <- Range(0, sArr.length)) {
      println(sArr(i))
    }

    for (i:Int <- 0 to sArr.length-1) {
      println(sArr(i))
    }

    for (i:Int <- 0 until  sArr.length) {
      println(sArr(i))
    }

    for (i:Int <- 0.until(  sArr.length)) {
      println(sArr(i))
    }

  }
}
